package com.cdel.akka.chapter2.actor;

import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.Status;
import akka.japi.pf.ReceiveBuilder;
import scala.PartialFunction;
//接收ping，返回pong
public class JavaPongActor extends AbstractActor {

	//AbstractActor类有一个receive方法，其子类必须实现这个方法或者在构造方法里调用该方法。这个方法返回PartialFunction，这个类来自scala api。
	//在java中，并没有提供任何原生方法来构造PartialFunction（并不对所有可能输入进行处理的函数），因此akka为我们提供了一个抽象的构造方法类ReceiveBuilder，
	public PartialFunction receive(){
    	return ReceiveBuilder
    		//连续调用ReceiveBuilder的方法，为所有需要匹配处理的输入消息类型提供响应方法的描述，然后调用build方法生成需要返回的PartialFunction
            //调用sender方法后，就可以返回所收到的消息的响应了，响应的对象可能是一个actor，也可能是来自actor系统外部的请求。
    		//第一种情况相当直接，返回的消息会直接发送到该actor的收件箱中。第二种情况后面再说。
    		//sender函数会返回一个ActorRef，我们调用了sender().tell()。tell是最基本的单向消息传输模式。第一个参数是我们想要发送至对方信箱的消息。
    		//第二个参数是对方actor看到的发送者。
    		//.matchEquals("Ping", s -> {Thread.sleep(500);sender().tell("Pong", ActorRef.noSender());})
    		.matchEquals("Ping", s -> {sender().tell("Pong", ActorRef.noSender());})
            //Status.Failure为了向发送发报告错误，需要向其发送一条消息，如果actor中抛出了异常，就会通知对其进行监督的actor，不过无论如何，如果想要
            //报告错误消息，需要将错误发送给发送方，如果发送方使用了Future来接收响应，那么返回错误消息会导致future的结果为失败。
            .matchAny(x -> sender().tell(new Status.Failure(new Exception("unknow message")), self()))
            .build();
    }

	/**
	 * match(class, function)：描述了对于任何匹配的该类型的消息，应该如何响应：
	 * match(String.class, s -> {if(s.equals("Ping")) respondToPing(s);})
	 * match(class, predicate, function)：描述了对于predicate条件函数为真的某特定类型的消息，应该如何响应：
	 * match(String.class, s -> s.equals("Ping"), s -> respondToPing(s))
	 * matchEquals(object, function)：描述了对于和传入的第一个参数相等的消息，应该如何响应：
	 * matchEquals("Ping", s -> respondToPing(s))
	 * matchAny(function)：匹配所有尚未匹配的消息，通常来说，应该返回错误信息，或者至少将错误记录到日志。
	 * */

}
